using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using AreaBuilder.Forms;

namespace AreaBuilder.Forms {
    public partial class frmOverview : Form {
        private readonly AreaHolder ah;
        private readonly String type;
        private bool alive = true;
        private ArrayList notOrig;
        private ArrayList original;

        public frmOverview() {
            InitializeComponent();

            setTitle();
        }

        public frmOverview(AreaHolder ah, String type) {
            InitializeComponent();

            this.ah = ah;
            this.type = type;

            setTitle();
        }

        private void setTitle() {
            if (type.Equals("mobs")) {
                Text = "Mobs Overview";
            } else if (type.Equals("helps")) {
                Text = "Helps Overview";
            } else if (type.Equals("items")) {
                Text = "Items Overview";

                foreach (Item i in ah.area.Items) {
                    foreach (ItemTrigger it in i.Triggers) {
                        it.TriggerSpell = Regex.Replace(it.TriggerSpell, @"~{2,}", "");

                        // Multiple ~ fix
                    }
                }
            } else if (type.Equals("rooms")) {
                Text = "Rooms Overview";
            } else if (type.Equals("specials")) {
                Text = "Specials Overview";
            } else if (type.Equals("shops")) {
                Text = "Shops Overview";
            } else if (type.Equals("resets")) {
                Text = "Resets Overview";
            } else if (type.Equals("progs")) {
                Text = "MobProgs Overview";
            }
        }

        private void frmOverview_Load(object sender, EventArgs e) {
            fillList();

            var t = new Thread(checkChanges);
            t.Start();
        }

        private void fillList() {
            lstOverview.Items.Clear();

            if (type.Equals("mobs")) {
                original = new ArrayList(ah.area.Mobs.ToArray());

                IOrderedEnumerable<Mobile> query = from Mobile m in ah.area.Mobs
                                                   orderby m.VNum
                                                   select m;

                foreach (Mobile m in query)
                    lstOverview.Items.Add(String.Format("#{0} - {1}", m.VNum, m.Name));
            } else if (type.Equals("helps")) {
                original = new ArrayList(ah.area.Helps.ToArray());

                IEnumerable<Help> query = from Help h in ah.area.Helps
                                          select h;

                int i = 0;

                foreach (Help h in query)
                    lstOverview.Items.Add(String.Format("{0} - {1}", ++i, h.Keywords));
            } else if (type.Equals("items")) {
                original = new ArrayList(ah.area.Items.ToArray());

                IOrderedEnumerable<Item> query = from Item i in ah.area.Items
                                                 orderby i.VNum
                                                 select i;

                foreach (Item i in query)
                    lstOverview.Items.Add(String.Format("#{0} - {1}", i.VNum, i.Name));
            } else if (type.Equals("rooms")) {
                original = new ArrayList(ah.area.Rooms.ToArray());

                IOrderedEnumerable<Room> query = from Room r in ah.area.Rooms
                                                 orderby r.VNum
                                                 select r;

                foreach (Room r in query)
                    lstOverview.Items.Add(String.Format("#{0} - {1}", r.VNum, r.Title));
            } else if (type.Equals("specials")) {
                original = new ArrayList(ah.area.Specials.ToArray());

                IOrderedEnumerable<Special> query = from Special s in ah.area.Specials
                                                    orderby s.VNum
                                                    select s;

                foreach (Special s in query)
                    lstOverview.Items.Add(String.Format("#{0}/{1} - {2}", s.VNum, s.Type, getMobByVnum(s.VNum)));

                btnEditView.Enabled = false;
            } else if (type.Equals("shops")) {
                original = new ArrayList(ah.area.Shops.ToArray());

                IOrderedEnumerable<Shop> query = from Shop s in ah.area.Shops
                                                 orderby s.VNum
                                                 select s;

                foreach (Shop s in query)
                    lstOverview.Items.Add(String.Format("#{0} - {1}", s.VNum, getMobByVnum(s.VNum)));
            } else if (type.Equals("resets")) {
                original = new ArrayList(ah.area.Resets.ToArray());

                IEnumerable<Reset> query = from Reset r in ah.area.Resets
                                           select r;

                int i = 0;

                foreach (Reset r in query)
                    lstOverview.Items.Add(String.Format("{0} - {1}", ++i, getResetText(r)));
            } else if (type.Equals("progs")) {
                original = new ArrayList(ah.area.Progs.ToArray());

                IOrderedEnumerable<MobProg> query = from MobProg mp in ah.area.Progs
                                                    orderby mp.VNum
                                                    select mp;

                foreach (MobProg mp in query)
                    lstOverview.Items.Add(String.Format("#{0} - {1}", mp.VNum, getMobsByProg(mp.VNum)));
            }
        }

        private void checkChanges() {
            while (alive) {
                try {
                    if (type.Equals("mobs"))
                        notOrig = ah.area.Mobs;
                    else if (type.Equals("helps"))
                        notOrig = ah.area.Helps;
                    else if (type.Equals("items"))
                        notOrig = ah.area.Items;
                    else if (type.Equals("rooms"))
                        notOrig = ah.area.Rooms;
                    else if (type.Equals("specials"))
                        notOrig = ah.area.Specials;
                    else if (type.Equals("shops"))
                        notOrig = ah.area.Shops;
                    else if (type.Equals("resets"))
                        notOrig = ah.area.Resets;
                    else if (type.Equals("progs"))
                        notOrig = ah.area.Progs;

                    if (original.Count != notOrig.Count)
                        fillList();

                    Thread.Sleep(500);
                } catch (Exception) {
                    alive = false;
                    Dispose();
                }
            }
        }

        private String getMobByVnum(int vnum) {
            try {
                Mobile mob = (from Mobile m in ah.area.Mobs
                              where m.VNum == vnum
                              select m).Single();

                return mob.Name;
            } catch (InvalidOperationException) {}
            return "N/A";
        }

        private String getItemByVnum(int vnum) {
            try {
                Item item = (from Item i in ah.area.Items
                             where i.VNum == vnum
                             select i).Single();

                return item.Name;
            } catch (InvalidOperationException) {}

            return "N/A";
        }

        private String getRoomByVnum(int vnum) {
            try {
                Room room = (from Room r in ah.area.Rooms
                             where r.VNum == vnum
                             select r).Single();

                return room.Title;
            } catch (InvalidOperationException) {}

            return "N/A";
        }

        private String getMobsByProg(int vnum) {
            var mobs = new StringBuilder();

            IOrderedEnumerable<Mobile> query = from Mobile m in ah.area.Mobs
                                               orderby m.VNum
                                               select m;

            foreach (Mobile mob in query) {
                IOrderedEnumerable<MobProgLink> progs = from MobProgLink mpl in mob.Progs
                                                        where mpl.Program == vnum
                                                        orderby mpl.Program
                                                        select mpl;

#pragma warning disable 168
                foreach (MobProgLink mpl in progs) {
                    mobs.Append(mob.Name);
                    mobs.Append(", ");
                }
#pragma warning restore 168
            }

            String temp = mobs.ToString();

            return Regex.Replace(temp, @", $", "");
        }

        private String getResetText(Reset r) {
            var sb = new StringBuilder();

            switch (r.Type) {
                case "M":
                    sb.Append(String.Format("Load mob '{0}'", getMobByVnum(r.VNum)));
                    break;
                case "O":
                    sb.Append(String.Format("Load object '{0}'", getItemByVnum(r.VNum)));
                    break;

                case "P":
                    sb.Append(String.Format("Put '{0}' in '{1}'", getItemByVnum(r.VNum),
                                            getItemByVnum(Int32.Parse(r.VNumWear))));
                    break;

                case "G":
                    sb.Append(String.Format("Give '{0}' to mob", getItemByVnum(r.VNum)));
                    break;

                case "E":
                    sb.Append(String.Format("Equip mob w/ item '{0}'", getItemByVnum(r.VNum)));
                    break;

                case "D":
                    sb.Append(String.Format("Reset door in '{0}'", getRoomByVnum(r.VNum)));
                    break;

                case "R":
                    sb.Append(String.Format("Randomize exits in '{0}'", getRoomByVnum(r.VNum)));
                    break;
            }

            return sb.ToString();
        }

        private void btnEditView_Click(object sender, EventArgs e) {
            if (lstOverview.SelectedIndex < 0) {
                MessageBox.Show("You have to select an object to view/edit!", "Error!", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);

                return;
            }

            Form newForm = null;

            if (type.Equals("mobs"))
                newForm = new frmMobs(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("helps"))
                newForm = new frmHelp(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("items"))
                newForm = new frmObjects(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("rooms"))
                newForm = new frmRoom(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("shops"))
                newForm = new frmShops(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("progs"))
                newForm = new frmProg(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("resets"))
                newForm = new frmResets(ah, getID(lstOverview.SelectedItem.ToString()));
            else if (type.Equals("specials"))
                return;

            if (newForm != null) {
                newForm.MdiParent = MdiParent;

                newForm.Location = new Point((MdiParent.Size.Width - newForm.Size.Width)/2 + 40,
                                             (MdiParent.Size.Height - newForm.Size.Height)/2 - 60);
                newForm.Show();
            }
        }

        private static int getID(String text) {
            var re = new Regex(@"^#?(?<number>\d+)\b");
            Match m = re.Match(text);

            if (m.Success)
                return (Int32.Parse(m.Groups["number"].Value));

            return -1;
        }

        private void lstOverview_DoubleClick(object sender, EventArgs e) {
            btnEditView_Click(null, null);
        }

        private void frmOverview_FormClosing(object sender, FormClosingEventArgs e) {
            alive = false;
        }

        private void btnDelete_Click(object sender, EventArgs e) {
            if (lstOverview.SelectedIndex < 0) {
                MessageBox.Show("You have to select an object to view/edit!", "Error!", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);

                return;
            }

            if (type.Equals("mobs")) {} else if (type.Equals("helps")) {} else if (type.Equals("items")) {} else if (type.Equals("rooms")) {} else if (type.Equals("shops")) {} else if (type.Equals("progs")) {} else if (type.Equals("resets")) {} else if (type.Equals("specials")) {}
        }
    }
}